// 数据统计
const Service = require("egg").Service;
const _ = require("lodash");
const dayjs = require("dayjs");
class StatisticsService extends Service {
	async getConstantData() {
		// console.log("getConstantData");
		let { knex } = this.app;
		const today = new Date();
		const oneMonthAgo = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
		let { carTotal } = await knex("basic").count("* as carTotal").where({ isDelete: 0 }).first();
		// 车辆出租率
		let { rentTotal } = await knex("order")
			.whereBetween("operationAt", [oneMonthAgo, today])
			.whereNot("status", "已还押金")
			.count("* as rentTotal")
			.first();
		let rentRate = _.round(rentTotal / carTotal, 2);
		// 未出租车辆数
		let noRentTotal = carTotal - rentTotal;
		// 车辆违章率
		let { violationTotal } = await knex("violation")
			.whereBetween("operationAt", [oneMonthAgo, today])
			.count("* as violationTotal")
			.first();

		let violationRate = _.round(violationTotal / carTotal, 2);
		// 维修率
		let { repairTotal } = await knex("repair")
			.whereBetween("operationAt", [oneMonthAgo, today])
			.count("* as repairTotal")
			.first();
		let repairRate = _.round(repairTotal / carTotal, 2);

		// 全部客户
		let { customerTotal } = await knex("customer")
			.whereBetween("operationAt", [oneMonthAgo, today])
			.count("* as customerTotal")
			.first();
		// 已租客户
		let { rentCustomerTotal } = await knex("order")
			.whereBetween("operationAt", [oneMonthAgo, today])
			.whereNot("status", "已还押金")
			.countDistinct("customerId as rentCustomerTotal")
			.first();
		// let { rentCustomerTotal } = await knex("order")
		// 	.whereBetween("operationAt", [oneMonthAgo, today])
		// 	.whereNot("status", "已还押金")
		// 	.count("customerId as rentCustomerTotal")
		// 	.first();
		return {
			carTotal,
			rentTotal,
			rentRate,
			violationTotal,
			violationRate,
			repairTotal,
			repairRate,
			noRentTotal,
			customerTotal,
			rentCustomerTotal,
		};
	}
	async getStatisticsChartData(actionData) {
		let { startDate, endDate } = actionData;
		let { knex } = this.app;
		// 获取日期区间
		let dayLabels = this.getDatesBetween({ startDate, endDate });
		// 避免统计不了当天数据
		startDate = dayjs(startDate).subtract(1, "day").format("YYYY-MM-DD");
		endDate = dayjs(endDate).add(1, "day").format("YYYY-MM-DD");
		// 当日已租
		let rentalCountResult = await this.getRentDay(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		// 当日已还
		let returnCarCountResult = await this.getReturnData(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		// 当日已收
		let dailyRevenue = await this.getDailyRevenue(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		// 当日已付
		let dailyExpenses = await this.getDailyExpenses(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		// 当日维修
		let repairCount = await this.getRepairCount(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		// 当日保养
		let maintenanceCount = await this.getMaintenanceCount(knex, { startDate, endDate }, this.mapDayLabels(dayLabels));
		return {
			rentalCountResult,
			returnCarCountResult,
			dailyRevenue,
			dailyExpenses,
			repairCount,
			maintenanceCount,
		};
	}
	// 构造结构
	mapDayLabels(dayLabels) {
		let obj = {};
		dayLabels.forEach(item => {
			obj[item] = 0;
		});
		return obj;
	}
	// 当日维修
	async getRepairCount(knex, { startDate, endDate }, dayData) {
		let repairDateCountResult = await knex("repair")
			.select(knex.raw("DATE(repairDate) AS repairDate, COUNT(*) AS repairCount"))
			.whereBetween("repairDate", [startDate, endDate])
			.whereNotNull("repairDate")
			.groupByRaw("DATE(repairDate)");
		repairDateCountResult.forEach(item => {
			item.repairDate = dayjs(item.repairDate).format("YYYY-MM-DD");
			if (_.has(dayData, item.repairDate)) {
				dayData[item.repairDate] = item.repairCount;
			}
		});
		return dayData;
	}
	// 当日保养
	async getMaintenanceCount(knex, { startDate, endDate }, dayData) {
		let maintenanceDateCountResult = await knex("maintenance")
			.select(knex.raw("DATE(maintenanceDate) AS maintenanceDate, COUNT(*) AS maintenanceCount"))
			.whereBetween("maintenanceDate", [startDate, endDate])
			.whereNotNull("maintenanceDate")
			.groupByRaw("DATE(maintenanceDate)");
		maintenanceDateCountResult.forEach(item => {
			item.maintenanceDate = dayjs(item.maintenanceDate).format("YYYY-MM-DD");
			if (_.has(dayData, item.maintenanceDate)) {
				dayData[item.maintenanceDate] = item.maintenanceCount;
			}
		});
		return dayData;
	}
	// 当日已还数据
	async getReturnData(knex, { startDate, endDate }, dayData) {
		let returnCarCountResult = await knex("order")
			.select(knex.raw("DATE(operationAt) AS returnDate, COUNT(*) AS returnCarCount"))
			.where("status", "已验车")
			.whereBetween("operationAt", [startDate, endDate])
			.whereNotNull("operationAt")
			.groupByRaw("DATE(returnDate)");
		returnCarCountResult.forEach(item => {
			item.returnDate = dayjs(item.returnDate).format("YYYY-MM-DD");
			dayData[item.returnDate] = item.returnCarCount;
		});
		return dayData;
	}
	// 当日已租数据
	async getRentDay(knex, { startDate, endDate }, dayData) {
		let rentalCountResult = await knex("contract")
			.select(knex.raw("DATE(signingTime) AS rentalDate, COUNT(*) AS rentalCount"))
			.whereBetween("signingTime", [startDate, endDate])
			.whereNotNull("signingTime")
			.groupByRaw("DATE(rentalDate)");
		rentalCountResult.forEach(item => {
			item.rentalDate = dayjs(item.rentalDate).format("YYYY-MM-DD");
			// dayData[item.rentalDate] = item.rentalCount;
			if (_.has(dayData, item.rentalDate)) {
				dayData[item.rentalDate] = item.rentalCount;
			}
		});
		return dayData;
	}
	// 当日已收
	async getDailyRevenue(knex, { startDate, endDate }, dayData) {
		let dailyRevenue = await knex("running_account")
			.select(knex.raw("DATE(operationAt) AS revenueDate, SUM(flowAmount) AS revenueTotal"))
			.where({
				flowType: "收款申请",
				flowStatus: "已付",
			})
			.whereBetween("operationAt", [startDate, endDate])
			.whereNotNull("operationAt")
			.groupByRaw("DATE(revenueDate)");
		dailyRevenue.forEach(item => {
			item.revenueDate = dayjs(item.revenueDate).format("YYYY-MM-DD");
			if (_.has(dayData, item.revenueDate)) {
				dayData[item.revenueDate] = item.revenueTotal;
			}
		});
		return dayData;
	}
	// 当日已付
	async getDailyExpenses(knex, { startDate, endDate }, dayData) {
		let dailyExpenses = await knex("running_account")
			.select(knex.raw("DATE(operationAt) AS expensesDate,  SUM(flowAmount) AS expensesTotal"))
			.where({
				flowType: "付款申请",
				flowStatus: "已付",
			})
			.whereBetween("operationAt", [startDate, endDate])
			.whereNotNull("operationAt")
			.groupByRaw("DATE(expensesDate)");
		dailyExpenses.forEach(item => {
			item.expensesDate = dayjs(item.expensesDate).format("YYYY-MM-DD");
			if (_.has(dayData, item.expensesDate)) {
				dayData[item.expensesDate] = item.expensesTotal;
			}
		});
		return dayData;
	}
	// 返回一个周期内的日期数组
	getDatesBetween({ startDate, endDate }) {
		const dates = [];
		const start = dayjs(startDate);
		const end = dayjs(endDate);
		// 获取两个日期之间的天数差
		let diffDays = end.diff(start, "day");
		diffDays = diffDays > 10 ? 10 : diffDays;
		// 循环生成日期数组
		for (let i = 0; i <= diffDays; i++) {
			const date = start.add(i, "day");
			dates.push(date.format("YYYY-MM-DD"));
		}
		return dates;
	}
}
module.exports = StatisticsService;
